package com.sugon.modules.workflow.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.cait.bpmsuite.api.BPMClient;
import com.cait.bpmsuite.api.BPMClientManager;
import com.cait.bpmsuite.api.BPMExecuteService;
import com.cait.bpmsuite.api.BPMServiceLocation;
import com.cait.bpmsuite.api.bpmmodle.BPMActivity;
import com.cait.bpmsuite.api.bpmmodle.BPMProcessInstance;
import com.cait.bpmsuite.api.bpmmodle.BPMResult;
import com.cait.bpmsuite.api.bpmmodle.BPMWorkItem;
import com.sugon.dao.MaterialBaseDao;
import com.sugon.entity.MaterialBaseEntity;
import com.sugon.entity.SysUserEntity;
import com.sugon.modules.workflow.IWorkFlowManager;
import com.sugon.modules.workflow.consts.OaWorkflowProcesses;
import com.sugon.service.SysConfigService;
import com.sugon.service.SysOaProcessService;
import com.sugon.service.SysUserService;
import com.sugon.utils.RRException;
import com.sugon.utils.ShiroUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;

@Slf4j
@Service
public class WorkFlowManagerImpl implements IWorkFlowManager {

    @Autowired
    private SysConfigService configService;
    @Autowired
    private SysUserService userService;
    @Autowired
    private MaterialBaseDao materialBaseDao;
    @Autowired
    private SysOaProcessService oaProcessService;

    @Override
    public BPMResult gobackActivityInstance(String actInstId, String msg) {
        BPMResult bpmResult = null;
        BPMExecuteService bpmExecuteService = getBpmExecuteService();
        // 获取当前活动实例允许回退的活动列表
        BPMActivity[] allowGobackActivityList = bpmExecuteService.getAllowGobackActivityListOfActivityInstance(actInstId);
        if (ArrayUtil.isNotEmpty(allowGobackActivityList)) {
            // 默认第一个吧
            bpmResult = bpmExecuteService.gobackActivityInstance(actInstId, allowGobackActivityList[0].getId(), new String[]{}, msg);
        }
        return bpmResult;
    }

    @Override
    public BPMWorkItem getWorkItemById(String workItemId) {
        String bpmAppId = configService.getBpmAppId();
        String bpmServiceUrl = getBpmServiceUrl();
        BPMServiceLocation bl = new BPMServiceLocation(bpmAppId, null, bpmServiceUrl);
        BPMClient client = BPMClientManager.getInstance().connect(bl);
        return client.getBPMExecuteService().getWorkItemById(workItemId);
    }

    @Override
    public String getBpmServiceUrl() {
        return configService.getRemoteServiceHost() + "/BPMServer/service";
    }

    @Override
    public boolean completeWorkItem(String workItemId) {
        /*
            干两件事：
            1、完成备件领用审批项
            2、每次审批项完毕，校验该审批流程实例是否已结束
            如果结束的话，需要修改审核状态为已通过
         */
        BPMExecuteService bpmExecuteService = getBpmExecuteService();
        BPMResult re = bpmExecuteService.completeWorkItem(workItemId);
        boolean completeFlag = re != null && re.isSuccess();
        if (!completeFlag) {
            String message = "调用BPM API client.getBPMExecuteService().completeWorkItem 失败，workItemId为:" + workItemId;
            try {
                message = new String(message.getBytes("ISO-8859-1"), "GBK");
            } catch (UnsupportedEncodingException e) {
                message = e.getMessage();
                throw new RRException(message, e);
            }
        }
        return completeFlag;
    }

    @Override
    public BPMProcessInstance createProcessInstance(String procDefId, String procInstTitle, String startProcessUserId) {
        // 准备发起流程
        BPMExecuteService bpmExecuteService = getBpmExecuteService();
        return bpmExecuteService.createProcessInstance(procDefId, procInstTitle, startProcessUserId);
    }

    @Override
    public BPMProcessInstance getByProcInstId(String procInstId) {
        // 准备发起流程
        BPMExecuteService bpmExecuteService = getBpmExecuteService();
        return bpmExecuteService.getProcessInstanceById(procInstId);
    }

    @Override
    public void completeMyWorkItem(String procInstId, String unionId, String busType, String busId, String remark) {
        BPMExecuteService bpmExecuteService = getBpmExecuteService();
        // 找到第一个工作项，并完成
        BPMWorkItem[] workItems = bpmExecuteService.getWorkItemListOfProcessInstance(procInstId, unionId, 2, 0, false);
        if (ArrayUtil.isEmpty(workItems)) {
            log.error("未找到发起人需要完成的第一个工作项，流程ID: {}，发起人ID: {}", procInstId, unionId);
            return;
        }
        for (BPMWorkItem workItem : workItems) {
            // 得到当前用户的启动工作项
            if (ShiroUtils.getUnionId().equals(workItem.getOwnerId())) {
                // 完成工作项
                if (workItem != null && workItem.getState() == 2) {
                    boolean completeFlag = completeWorkItem(workItem.getId());
                    if (completeFlag) {
                        // 生成OA流程工作项处理记录
                        oaProcessService.generateProcessHandleRecord(busType, busId, workItem, 1, remark);
                        log.info("用户[{}]完成第一项工作项[发起申请]成功!", ShiroUtils.getUnionId());
                    } else {
                        log.error("工作项完成失败，结果：[{}]!", JSON.toJSONString("re"));
                    }
                } else {
                    log.error("工作项完成失败，结果：[{}]!", JSON.toJSONString(workItem));
                }
                break;
            }
        }
    }

    private BPMExecuteService getBpmExecuteService() {
        // 准备发起流程
        String ermsAppId = configService.getErmsAppId();
        String bpmServiceUrl = getBpmServiceUrl();
        // 声明流程发起点
        BPMServiceLocation bl = new BPMServiceLocation(ermsAppId, null, bpmServiceUrl);
        BPMClient client = BPMClientManager.getInstance().connect(bl);
        // 获取bmp执行Service来做后续操作
        return client.getBPMExecuteService();
    }

    @Override
    public void setProcessInstanceRelatedData(String procInstId, String key, Object value) {
        // 准备发起流程
        BPMExecuteService bpmExecuteService = getBpmExecuteService();
        BPMResult bpmResult = bpmExecuteService.setProcessInstanceRelatedData(procInstId, key, value);
    }

    @Override
    public BPMResult startProcessInstance(String procInstId) {
        // 准备发起流程
        BPMExecuteService bpmExecuteService = getBpmExecuteService();
        return bpmExecuteService.startProcessInstance(procInstId);
    }

    @Override
    public boolean terminateProcessInstance(String materialBaseId, String procInstId) {
          /*
            干两件事：
            1、完成备件领用审批项
            2、每次审批项完毕，校验该审批流程实例是否已结束
            如果结束的话，需要修改审核状态为已通过
         */
        boolean completeFlag = terminateProcessInstance(procInstId);
        if (completeFlag) {
            // 如果取消成功，生成OA流程工作项处理记录
            BPMWorkItem bpmWorkItem = new BPMWorkItem();
            bpmWorkItem.setName("取消领料");
            bpmWorkItem.setProcInstId(procInstId);
            oaProcessService.generateProcessHandleRecord(OaWorkflowProcesses.MATERIAL.getBusType(), materialBaseId, bpmWorkItem, 1, "取消领料成功");
        }
        return completeFlag;
    }

    @Override
    public boolean terminateProcessInstance(String procInstId) {
        BPMExecuteService bpmExecuteService = getBpmExecuteService();
        BPMResult re = bpmExecuteService.terminateProcessInstance(procInstId);
        log.info("终止OA流程[{}]结果:{}", JSON.toJSONString(re));
        return re != null && re.isSuccess();
    }

    @Override
    public void startAndCompleteFirstWorkItem(String materialBaseId, String startProcessUserId, String title, String approver) {
        // 此时的startProcessUserId是erms的用户ID，需要换成长安统一认证中心的用户ID
        SysUserEntity user = userService.queryObject(startProcessUserId);
        Assert.notNull(user, "备件领用流程发起人[{}]不存在", startProcessUserId);
        // 获取领料单信息
        MaterialBaseEntity materialBase = materialBaseDao.queryObject(materialBaseId);
        Assert.notNull(materialBase, "领料单信息[{}]不存在", materialBaseId);
        startProcessUserId = user.getUnionId();
        if (StrUtil.isEmpty(startProcessUserId)) {
            log.error("发起备件领用流程用户的UNION_ID不存在，请确认用户是否登录过或系统参数IS_AUTH是否设置正确！");
            throw new RRException("尚未获取到流程发起用户的unionId，无法发起备件领用流程！");
        }

        // 准备发起流程
        String bpmAppId = configService.getBpmAppId();
        BPMExecuteService bpmExecuteService = getBpmExecuteService();

        /*
            一个领料单只可以发起一个流程
            在发起新的领料审核时，需要删除之前发起的记录
         */
        String procInstId = materialBase.getProcInstId();
        if (StrUtil.isNotEmpty(procInstId)) {
            log.info("领料单[{}]之前已发起过领料，需要终止之前流程[{}]，创建新的流程！", title, procInstId);
            BPMResult bpmResult = bpmExecuteService.terminateProcessInstance(procInstId);
            log.info("终止领料单[{}]之前发起流程[{}]结果：{}", title, procInstId, JSON.toJSONString(bpmResult));
        }
        // 创建流程
        BPMProcessInstance procInst = bpmExecuteService.createProcessInstance(bpmAppId, "工具领料单：" + title, startProcessUserId);
        // 如果流程创建不成功，不执行后续流程
        if (procInst == null) {
            log.error("流程创建失败，流程定义ID：{}", bpmAppId);
            return;
        }
        // 发起流程，获取发起流程结果，如果为空，表示发起流程失败，不做后续处理
        BPMResult result;
        if (procInst.getId() != null) {
            // 设置室主任审核人员,officeApprover为自定义参与者
            bpmExecuteService.setProcessInstanceRelatedData(procInst.getId(), "officeApprover", approver);
            try {
                // 启动流程
                result = bpmExecuteService.startProcessInstance(procInst.getId());
                if (result == null || !result.isSuccess()) {
                    log.error("启动[{}]流程失败，失败原因：{}", procInst.getName(), JSON.toJSONString(result));
                    return;
                }
            } catch (Exception e) {
                log.error("启动[{}]流程时出现异常，异常：{}", procInst.getName(), JSON.toJSONString(e));
            }
        }
        // 回填流程实例ID到领料单中
        materialBaseDao.updateProcInstId(materialBaseId, procInst.getId());
        log.info("启动领料单[{}]OA审批流程成功，并更新完领料单中procInstId字段！", title);
        // 找到第一个工作项，并完成
        BPMWorkItem[] workItems = bpmExecuteService.getWorkItemListOfProcessInstance(procInst.getId(), startProcessUserId, 2, 0, false);
        if (ArrayUtil.isEmpty(workItems)) {
            log.error("未找到发起人需要完成的第一个工作项，流程ID: {}，发起人ID: {}", procInst.getId(), startProcessUserId);
            return;
        }
        for (BPMWorkItem workItem : workItems) {
            // 得到当前用户的启动工作项
            if (startProcessUserId.equals(workItem.getOwnerId())) {
                // 完成工作项
                if (workItem != null && workItem.getState() == 2) {
                    BPMResult re = bpmExecuteService.completeWorkItem(workItem.getId());
                    if (re != null && re.isSuccess()) {
                        // 生成OA流程工作项处理记录
                        oaProcessService.generateProcessHandleRecord(OaWorkflowProcesses.MATERIAL.getBusType(), materialBaseId, workItem, 1, "发起备件领用申请");
                        log.info("用户[{}]完成第一项工作项[发起申请]成功!", startProcessUserId);
                    } else {
                        log.error("工作项完成失败，结果：[{}]!", JSON.toJSONString(re));
                    }
                } else {
                    log.error("工作项完成失败，结果：[{}]!", JSON.toJSONString(workItem));
                }
                break;
            }
        }
    }
}
